package nimbus.commands
{
	import flash.events.EventDispatcher;
	
	import nimbus.commands.base.ICommand;
	import nimbus.events.ExecutionEvent;
	import nimbus.events.ProcessingMessageEvent;
	import nimbus.utils.detectAbstractInstantiation;
	import nimbus.utils.detectAbstractMethodCall;
	
	/**
	 * Dispatched after the command is complete.  The extending class must dictate when the command
	 * is complete by calling dispatchSuccess() or dispatchFailure(), which will in turn dispatch
	 * the ExecutionEvent and notify the controller.
	 */
	[Event(name="executionComplete", type="nimbus.events.ExecutionEvent")]
	
	/**
	 * Dispatched each time the processing message property value changes.
	 */
	[Event(name="processingMessageChanged", type="nimbus.events.ProcessingMessageEvent")]
	
	/**
	 * The command base to be used for handling asynchronous operations. One example is a call to a
	 * remote server. Such a command must wait for the call to be processed by the server and 
	 * returned before the command is complete.  In order for other portions of the application
	 * (including the controller) to know when execution is complete, the extending class must
	 * call dispatchSuccess() or dispatchFailure(), which will in turn dispatch an ExecutionEvent.
	 * 
	 * <p>This class also serves as the base class for ParallelCommand and SequenceCommand.</p>
	 * 
	 * @see nimbus.commands.ParallelCommand
	 * @see nimbus.commands.SequenceCommand
	 */
	public class AsyncCommand extends EventDispatcher implements ICommand
	{
		/**
		 * Whether to block user interaction while the command is executing.
		 * 
		 * @see nimbus.Controller#deriveInteractionBlocking()
		 * 
		 * @default false
		 */
		public var blockUserInteraction:Boolean = false;
		
		/**
		 * @private
		 */
		private var _processingMessage:String = null;
		
		/**
		 * The processing message to be used as feedback to the user while the command is
		 * executing.
		 * 
		 * @see nimbus.Controller#deriveProcessingMessage
		 * @see nimbus.events.ProcessingMessageEvent
		 * 
		 * @default null
		 */
		public function get processingMessage():String
		{
			return _processingMessage;
		}
		
		/**
		 * @private
		 */
		public function set processingMessage(value:String):void
		{
			if (_processingMessage != value)
			{
				_processingMessage = value;
				dispatchEvent(new ProcessingMessageEvent(
						ProcessingMessageEvent.PROCESSING_MESSAGE_CHANGED, value));
			}
		}
		
		/**
		 * @private
		 */
		private var _type:String;
		
		/**
		 * @inheritDoc
		 */
		public function get type():String
		{
			return _type;
		} 
		
		/**
		 * @private
		 */
		public function set type(value:String):void
		{
			_type = value;
		}
		
		/**
		 * Constructor.
		 */
		public function AsyncCommand()
		{
			detectAbstractInstantiation(this, AsyncCommand);
		}
		
		/**
		 * @inheritDoc
		 */
		public function execute():void
		{
			detectAbstractMethodCall();
		}
		
		/**
		 * Called by the extending class once the command has completed executing successfully.
		 * This dispatches an ExecutionEvent which notifies the controller that the command
		 * has finished executing.
		 */
		protected function dispatchSuccess():void
		{
			dispatchEvent(new ExecutionEvent(ExecutionEvent.EXECUTION_COMPLETE, this, true));
		}
		
		/**
		 * Called by the extending class once the command has completed executing but a failure
		 * has been reached. This dispatches an ExecutionEvent which notifies the controller that 
		 * the command has finished executing.
		 */
		protected function dispatchFailure():void
		{
			dispatchEvent(new ExecutionEvent(ExecutionEvent.EXECUTION_COMPLETE, this, false));
		}
	}
}